package tp.pr5.items;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;

import tp.pr5.Constants;
import tp.pr5.Observable;


/**
 * A container of items. It can be employed by any class that stores items. A container cannot store two items with the same identifier.It provides methods to add new items, access them and remove them from the container.
 * @author VICTOR & HENAR
 */
public class ItemContainer extends Observable<InventoryObserver> {
	
	ArrayList<Item> items = null;
	private enum Action {CHANGE, SCANITEM, SCANINVENTORY, EMPTY};

	/**
	 * Creates the empty container
	 */
	public ItemContainer() {
		super();
		this.items = new ArrayList<Item>();
	}
	
	/**
	 * Returns the number of items contained
	 * @return the number of items in the container
	 */

	public int numberOfItems() 
	{
		return this.items.size();
	}

	/**
	 * Add an item to the container. The operation can fail, returning false
	 * @param item - The name of the item to be added.
	 * @return true if and only if the item is added, i.e., an item with the same identifier does not exists in the container
	 */
	public boolean addItem(Item item) 
	{
	   	if (!this.containsItem(item.getId()))
	   	{
	   		this.items.add(item);
	   		Collections.sort(this.items);
	   		notifiesObserver(this.items, null, Action.CHANGE);
	   		return true;
	   	}
	   	return false;
	}

	/**
	 * Returns the item from the container according to the item name
	 * @param id- Item name
	 * @return item with that name or null if the container does not store an item with that name.
	 */
	public Item getItem(String id) {
		if (id != null)
		{
	    	Item itemGetted = null;
	
	        for (int i = 0 ; i < this.items.size() ; i++) 
	        {
	        	itemGetted = this.items.get(i);
	            if(id.equalsIgnoreCase(itemGetted.getId())) 
	            	return itemGetted;
	        }
		}
		return null;
	}

	/**
	 * Returns and deletes an item from the inventory. This operation can fail, returning null
	 * @param id - Name of the item
	 * @return An item if and only if the item identified by id exists in the inventory. Otherwise it returns null
	 */
	public Item pickItem(String id) {
		if (id != null)
		{
			Item itemPicked;
	        for (int i = 0 ; i < this.items.size() ; i++) {
	        	itemPicked = this.items.get(i);
	            if(id.equalsIgnoreCase(itemPicked.getId())) 
	            {
	            	this.items.remove(i);
	            	Collections.sort(this.items);
	    	   		notifiesObserver(this.items, null, Action.CHANGE);
	            	return itemPicked;
	            }
	        }
		}
		return null;
	}

	/**
	 * Generates a String with information about the items contained in the container. Note that the items must appear sorted but the item name.
	 */
	public String toString() {
		String sItems = "";
		for (int i = 0; i < numberOfItems(); i++) {
			if (this.items.get(i).canBeUsed()) {
				sItems += "   " + this.items.get(i).getId();
				sItems +=  Constants.LINE_SEPARATOR;
			}
		}
		sItems = sItems.substring(0,sItems.length() - 1);
		return sItems;
	}
	
	/**
	 * Checks if the Item with this id exists in the container.v
	 * @param id - Name of the item.
	 * @return true if the container as an item with that name.
	 */
	public boolean containsItem(String id)
	{
		if (id != null) {
			Item itemGetted = null;

			for (int i = 0; i < numberOfItems(); i++) {
				itemGetted = this.items.get(i);
				if (id.equalsIgnoreCase(itemGetted.getId()))
					return true;
			}
		}
		return false;
	}
	
	/**
	 * Use an item, removing the item from the inventory if the item can not be used any more
	 * @param item
	 */
	public void useItem(Item item)
	{
		this.items.remove(item);
		notifiesObserver(null, item.getId(), Action.EMPTY);
		notifiesObserver(this.items, null, Action.CHANGE);
	}

	public void requestScanCollection()
	{
		notifiesObserver(null, this.toString(), Action.SCANINVENTORY);
	}
	
	public void requestScanItem(String id)
	{
		notifiesObserver(null, this.getItem(id).toString(), Action.SCANITEM);
	}
	
	private void notifiesObserver(List<Item> inventory, String string, Action action)
	{
		Iterator<InventoryObserver> itr = this.list.iterator();
		while(itr.hasNext()) {
			InventoryObserver element = itr.next();
			switch (action)
			{
				case CHANGE:
				{
					element.inventoryChange(inventory);
					break;
				}
				case SCANITEM:
				{
					element.itemScanned(string);
					break;
				}
				case SCANINVENTORY:
				{
					element.inventoryScanned(string);
					break;
				}
				case EMPTY:
				{
					element.itemEmpty(string);
					break;
				}
			}
		}
	}
	
}

